package org.noahsark.test;

import java.util.HashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.easymock.EasyMock;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeSuite;

/**
 * Base class for unittest framework,It plays the role of the fixture. stage in BeforeSuite,SetUp starts a Seam
 * environment�?Provide access to components for the test class. stage in AfterSuite，TearDown closes a Seam
 * environment，release the resources.
 *
 * @version Seurat v1.0
 * @author Xiang Weiwei, 2012-6-19
 */
public abstract class BaseTest {

    protected final Log log = LogFactory.getLog(getClass());

    Map appliMap = new HashMap();

    /**
     * starts seam environment.
     */
    @BeforeSuite
    protected void setUpBeforeSuite() throws Exception {
        long start = System.currentTimeMillis();
        Lifecycle.beginApplication(appliMap);
        Initialization init = new Initialization(null);
        init.create().init();
        long end = System.currentTimeMillis();
        System.out.println("seam start time:" + (end - start));
    }

    /**
     * Before the unit test，Subclasses get the instance of the component being tested.
     */
    @BeforeClass
    protected void initTestEnvBeforClass() {

        try {

            System.out.println("!!!!!!!!" + this.getClass().getName() + "!!!!!!!!");

            Lifecycle.beginCall();
            initComponent();
            Lifecycle.endCall();
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    /**
     * After the unit test ,Release resources; Realization in the subclass.
     */
    @AfterClass
    protected void endTestEnvAfterClass() {
    }

    /**
     * Open Seam conversation before unittest.
     */
    @BeforeMethod
    protected void beginCallBeforeMethod() {
        try {
            Lifecycle.beginCall();
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    /**
     * Close Seam conversation after unittest.
     */
    @AfterMethod
    protected void endCallAfterMethod() {
        try {
            Lifecycle.endCall();
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    /**
     * After all unittest，close seam environment.
     */
    @AfterSuite
    protected void tearDownAfterSuite() {

        Lifecycle.endApplication(appliMap);
    }

    /**
     * initial Seam component. Realization in the subclass，Used to obtain the instance of the component being tested.
     */
    protected abstract void initComponent();

    /**
     * Obtain the instance of the Seam component.
     *
     * @param <T> Ordinary java class of generic
     * @param e pojo
     * @return instance of the Seam component
     */
    protected <T> T getComponentInstance(Class<T> e) {
        T clazz = (T) Component.getInstance(e);
        return clazz;
    }

    /**
     * Obtain the instance of the Seam component.
     *
     * @param <T> Ordinary java class of generic
     * @param e pojo
     * @param name component name
     * @return instance of the Seam component
     */
    protected <T> T getComponentInstance(Class<T> e, String name) {
        T clazz = (T) Component.getInstance(name);
        return clazz;
    }

    /**
     * Create a mock object method，Mock Object is created will be injected into the Seam environment. Replace the
     * original Seam components
     *
     * @param <T> Generic mock object
     * @param t Need to be mock objects
     * @return mock object
     */
    protected <T> T createMock(Class<T> t) {
        T mock = EasyMock.createControl().createMock(t);
        Component component = Component.forName(Component.getComponentName(t));
        ScopeType scope = component.getScope();
        String name = component.getName();

        if (scope != STATELESS) {
            scope.getContext().set(name, mock);
        }
        return mock;
    }
    protected <T> T createMock2(Class<T> t, String componentName) {
        T mock = EasyMock.createControl().createMock(t);
        Component component = Component.forName(componentName);
        ScopeType scope = component.getScope();
        String name = component.getName();

        if (scope != STATELESS) {
            scope.getContext().set(name, mock);
        }
        return mock;
    }
    /**
     * Create a mock object method by componentName，Mock Object is created will be injected into the Seam environment. Replace the
     * original Seam components
     *
     * @param <T> Generic mock object
     * @param t Need to be mock objects
     * @return mock object
     */
    protected <T> T createMock(Class<T> t, String componentName) {
        T mock = EasyMock.createControl().createMock(t);
        Contexts.getEventContext().set(componentName, mock);
        return mock;
    }

    /**
     * Remove mock object, let SEAM recreate component.
     * @param componentName String
     */
    protected void clearMock(String componentName){
        Component component = Component.forName(componentName);
        ScopeType scope = component.getScope();
        String name = component.getName();

        if (scope != STATELESS) {
            scope.getContext().set(name, null);
        }
    }

}
